package com.lyx.rpc.consumer;

import com.lyx.rpc.common.exception.RegistryException;
import com.lyx.rpc.consumer.common.RpcConsumer;
import com.lyx.rpc.proxy.api.ProxyFactory;
import com.lyx.rpc.proxy.api.async.IAsyncObjectProxy;
import com.lyx.rpc.proxy.api.config.ProxyConfig;
import com.lyx.rpc.proxy.api.object.ObjectProxy;
import com.lyx.rpc.proxy.jdk.JdkProxyFactory;
import com.lyx.rpc.registry.api.RegistryService;
import com.lyx.rpc.registry.api.config.RegistryConfig;
import com.lyx.rpc.registry.zookeeper.ZookeeperRegistryService;
import com.lyx.rpc.spi.factory.ExtensionFactory;
import com.lyx.rpc.spi.loader.ExtensionLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
 * @Author by lyx
 * 服务消费客户端
 */
public class RpcClient {
    private final Logger logger = LoggerFactory.getLogger(RpcClient.class);
    /**
     * 服务版本
     */
    private String serviceVersion;
    /**
     * 服务分组
     */
    private String serviceGroup;
    /**
     * 序列化类型
     */
    private String serializationType;
    /**
     * 超时时间
     */
    private long timeout;

    /**
     * 是否异步调用
     */
    private boolean async;

    /**
     * 是否单向调用
     */
    private boolean oneway;
    private RegistryService registryService;
    private String proxy;

    public RpcClient(String registryAddress, String registryType, String serviceVersion, String serviceGroup, String serializationType, long timeout, boolean async, boolean oneway, String proxy) {
        this.serviceVersion = serviceVersion;
        this.timeout = timeout;
        this.serviceGroup = serviceGroup;
        this.serializationType = serializationType;
        this.async = async;
        this.oneway = oneway;
        this.registryService = getRegistryService(registryAddress, registryType);
        this.proxy = proxy;
    }

    private RegistryService getRegistryService(String registryAddress, String registryType) {
        if (StringUtils.isEmpty(registryType)) {
            throw new IllegalArgumentException("registry type is null");
        }
        //TODO 后续SPI扩展
        RegistryService registryService = new ZookeeperRegistryService();
        try {
            registryService.init(new RegistryConfig(registryAddress, registryType));
        } catch (Exception e) {
            logger.error("RpcClient init registry service throws exception:{}", e);
            throw new RegistryException(e.getMessage(), e);
        }
        return registryService;
    }

    /**
     * 创建JdkProxyFactory类的对象后赋值给ProxyFactory接口类型的变量proxyFactory，
     * 再通过proxyFactory对象的init()方法创建ObjectProxy对象，
     * 最终通过proxyFactory对象的getProxy()创建代理对象。
     * 在create()方法中，使得创建接口动态代理对象的方法在一定程度上具备了扩展性，也为后续SPI技术的引入打下了良好的基础。
     *
     * @param interfaceClass
     * @param <T>
     * @return
     */
    public <T> T create(Class<T> interfaceClass) {
        ProxyFactory proxyFactory = ExtensionLoader.getExtension(ProxyFactory.class, this.proxy);
        proxyFactory.init(
            new ProxyConfig<>(
                interfaceClass,
                this.serviceVersion,
                this.serviceGroup,
                this.serializationType,
                this.timeout,
                RpcConsumer.getInstance(),
                this.async,
                this.oneway,
                this.registryService)
        );
        return proxyFactory.getProxy(interfaceClass);
    }

    public <T> IAsyncObjectProxy createAsync(Class<T> interfaceClass) {
        return new ObjectProxy<T>(
            interfaceClass,
            this.serviceVersion,
            this.serviceGroup,
            this.serializationType,
            this.timeout,
            RpcConsumer.getInstance(),
            this.async,
            this.oneway,
            this.registryService
        );
    }

    public void shutdown() {
        RpcConsumer.getInstance().close();
    }
}
